#ifndef _L12_PROTO_H
#define _L12_PROTO_H

#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <libgen.h>
#include <string.h>
#include <ctype.h>
#include <netcdf.h>

#include "hdf.h"
// #include "anc.h"
#include "ancproto.h"
#include "l12_parms.h"
#include "l1_struc.h"
#include "l1q_struc.h"
#include "l2_struc.h"
#include "target_struc.h"
#include "vcal_struc.h"
#include "filehandle.h"
#include "filter.h"
#include "l2_flags.h"
#include "input_struc.h"
#include "time_utils.h"
#include "genutils.h"
#include "aer_struc.h"
#include "l2prod.h"
#include "l2prod_struc.h"
#include "hdf_utils.h"
#include "alloc_2d.h"
#include "xcal.h"
#include "epr_api.h"
#include "scene_meta.h"
#include "l2_hdf_generic.h"
#include "flags_iop.h"
#include "table_io_wrapper.h"
#include <clo.h>
#include "navigation.h"

#ifndef MAX
#define MAX(A,B)    ((A) > (B) ? (A) : (B))  /* Greater of (A,B) */ 
#endif

#ifndef MIN
#define MIN(A,B)    ((A) < (B) ? (A) : (B))  /* Lesser  of (A,B) */
#endif


void filehandle_init(filehandle *file);

int32_t getFormat(filehandle *file);

int  getl1rec  (filehandle *l1file, instr *input_str, int32_t recnum, 
                l1str *l1rec,l1rec_HY1C *data_hic,int oscan,int flags);

int  loadl1    (filehandle *l1file, instr *input_str, l1str *l1rec);

int  loadl1_new    (filehandle *l1file, instr *input_str, l1str *l1rec,l1rec_HY1C *data_hic,int iscan);

int  loadl1_hic    (filehandle *l1file, instr *input_str, l1str *l1rec,l1rec_HY1C *data_hic,int iq);

int  openl1    (filehandle *l1file);
int  readl1    (filehandle *l1file, int32_t recnum, l1str *l1rec);
int HY1C_readl1_but_no_set_flags(filehandle *l1file,int32_t recnum,l1str *l1rec);
int HY1C_readl1_only_set_flags(filehandle *l1file,int32_t recnum,l1str *l1rec);
int  readl1_lonlat (filehandle *l1file, int32_t recnum, l1str *l1rec);
int  writel1   (filehandle *l1file, int32_t recnum, l1str *l1rec);
void closel1   (filehandle *l1file);

int  openl1_read_hdf (filehandle *l1file);
int  openl1_write_hdf (filehandle *l1file);
int  writel1_hdf (filehandle *l1file, int32_t recnum, l1str *l1rec);
void closel1_hdf (filehandle *l1file);

int  openl2    (filehandle *l2file );
int  writel2   (filehandle *l2file, int32_t recnum, l2str *l2rec);
int  closel2   (filehandle *l2file );

int  open_target  (filehandle *file );
int  read_target  (filehandle *file, int32_t recnum, tgstr *tgrec);
void close_target (filehandle *file );

int  open_aer  (filehandle *file );
int  read_aer  (filehandle *file, int32_t recnum, aestr *aerec);
void close_aer (filehandle *file );

void init_l1( l1str *l1rec, int32_t npix );
void init_l2( l2str *l2rec );
void init_l2_single(l2str *l2rec);
void init_l2rec_HY1C(l2rec_HY1C *l2rec, int type);

void free_l1q(void);
int32_t alloc_l1( int32_t npix, int32_t nbands, int32_t nbandsir, int32_t n_inprods, l1str *l1rec);
void free_l1( l1str *l1rec );
int32_t alloc_l2( int32_t npix, int32_t nbands, l2str *l2rec);
void free_l2( l2str *l2rec );

int32_t alloc_hic( int32_t npix,int32_t nscans, int32_t nbands, int32_t nbandsir, int32_t n_inprods, l1rec_HY1C *hic_all);

int32_t alloc_target( int32_t npix, int32_t nbands, tgstr *tgrec);
int32_t alloc_aer( int32_t npix, int32_t nbands, aestr *aerec);

l2prodstr *get_l2prod_index(char *name, int32 sensorID, int32 numBands, int32 numPixels,
                            int32 numScans, int32_t *wave);
void write_product_XML_file(char* filename);

int32 prodlist(int32 sensorID, int32 evalmask, char *inprod, char *defprod, char outprod[MAXPROD][32]);

void cpl1l2  ( l1str *l1rec, l2str *l2rec);
int  convl12 ( l1str *l1rec, l2str *l2rec, int32_t spix, int32_t epix, instr *input_str, aestr *aerec);
int  convl21 ( l2str *l2rec, tgstr *tgrec, int32_t spix, int32_t epix, instr *input_str, float *Lt, vcstr *vrec);

int32 l2_seawifs(filehandle *l1file, filehandle *l2file);
int32 l1b_seawifs(filehandle *l1file, filehandle *ofile,
                  int32 sscan, int32 escan, int32 dscan,
                  int32 spixl, int32 epixl, int32 dpixl);
int32 get_modis_calfile(int32 sd_id,char *file);

int setanc  ( l1str *l1rec, instr *input_str,l1rec_HY1C *data_hic);
int setflags( instr *input_str, l1str *l1rec );
void setflagbits( int level, l1str *l1rec, l2str *l2rec, int32_t ipix );
void l1_mask_set(l1str *l1rec, int32_t ip);
int modis_cloud_mask(l1str *l1rec, int32_t ip);
int modis_cirrus_mask(l1str *l1rec, int32_t ip);
void compute_alpha(float lon[], float lat[], float senz[], float sena[], double mnorm[3], 
                   int32 npix, float alpha[]);

void cpl1rec(l1str *l1new, l1str *l1old);
void HY1C_cpl1rec(l1str *new_, l1str *old);

int b128_msk_init( char *landfile, int msknum );
int b128_msk_get ( float lat, float lon, int msknum );

int32_t rdsensorinfo(int32_t sensorID, int32_t evalmask, char *pname, void **pval);
void lowercase(char *s);

void atmocor1(l1str *l1rec, int32_t ip);
int atmocor2(l2str *l2rec, aestr *aerec, int32_t ip);
void whitecaps(int32_t sensorID, int32_t evalmask, int32_t nwave, float ws, float ws_max, float rhof[]);
void rayleigh(int32_t sensorID, int32_t evalmask, int32_t nwave, int pol_opt,
              float solz, float senz, float phi, float taur[], 
              float Fo[], float pr, float ws,
              float Lr_i[], float Lr_q[], float Lr_u[]);
int aerosol(l2str *l2rec, int32_t aer_opt_in, aestr *aerec, int32_t ip, 
            float wave[], int32_t nwave, int32_t nir_s_in, int32_t nir_l_in,
            float F0_in[], float La1_in[], float La2_out[], 
            float t_sol_out[], float t_sen_out[], float *eps, float taua_out[],
            int32_t *modmin, int32_t *modmax, float *modrat);
void gaseous_transmittance(int gasmask, int32_t sensorID, int32_t evalmask, int32_t nwave, float mu0, float mu, 
            float ozone, float wv, float no2_tropo, float no2_strat, float no2_frac,
	    float t_gas_sol[], float t_gas_sen[]);

float ky_airmass(float theta);
float pp_airmass(float theta);

void get_rhown_nir(float Rrs[], float wave[], int32_t nir_s, int32_t nir_l, 
                   float aw[], float bbw[], float chl, float rhown[]);
void get_rhown_eval(float Rrs[], float wave[], int32_t nir_s, int32_t nir_l,
                   int32_t nwave, float aw[], float bbw[], float chl,
                   float solz, float senz, float phi, float rhown[]);
void get_rho_mumm(l2str *l2rec, int32_t ip, int32_t iw, float *rhom);
void get_rhown_mumm(l2str *l2rec, int32_t ip, int32_t nir_s, int32_t nir_l, float rhown[]);
void glint_rad(int32_t num_iter, int32_t nband, int32_t nir_s, int32_t nir_l, 
               float glint_coef, float air_mass, 
               float mu0, float F0[],float taur[], float  taua[], float La[], float TLg[]);

float fresnel_coef(float mu, float n);
float fresnel_sen(float senz,int return_tf);
void  fresnel_sol(float wave[],int32_t nwave,float solz,float ws,float brdf[],int return_tf);
void foqint_morel(float wave[],int32_t nwave,float solz,float senzp,
                  float phi,float chl,float brdf[]); 
void qint_morel(float wave[],int32_t nwave,float solz,float chl,float Qn[]);
void gothic_R(float wave[],int32_t nwave,float solz,float senz, float ws,float R[]); 
int ocbrdf(l2str *l2rec,int32_t ip,int32_t brdf_opt,float wave[],int32_t nwave,
           float solz,float senz,float phi,float ws,float chl,float nLw[],float Fo[], float brdf[]);

void nlw_outband(int32_t evalmask, int32_t sensorID, float wave[], int32_t nwave, float Lw[], float nLw[]);

int l2gen_usage(char *prog);
int msl12_input_defaults(filehandle *l1file, instr *input);
void msl12_input_init(instr *input);
int l2gen_init_options(clo_optionList_t* list, char* prog);
int msl12_option_input(int argc, char *argv[], clo_optionList_t* list,
        char *progName, instr *input, filehandle *l1file);
int msl12_input(int argc, char *argv[], char* progName, instr *input, filehandle *l1file);

int l1subpix(filehandle *l1file, l1str *l1rec);

float fresnel(float theta,float rel_index);
int windex(float wave, float twave[], int ntwave);
int invbindx(int band, int32_t *bindx, int nbands);
void bindex_set(int32_t wave[], int nwave, int dwave);
int windex_get(int32_t wave);
int bindex_get(int32_t wave);

float bin_climatology(char *l3file, int32_t day, float lon, float lat, char *prodname);

float get_default_chl(l2str *l2rec, float Rrs[]);
void  get_chl   (l2str *l2rec, int prodnum, float prod[]);
void  get_las   (l2str *l2rec, l2prodstr *p, float prod[]);
void  get_sma   (l2str *l2rec, int32_t prodID, float prod[]);
void  get_tsm   (l2str *l2rec, int prodnum, float prod[]);
void  get_poc   (l2str *l2rec, int prodnum, float prod[]);
void  get_flh   (l2str *l2rec, float flh[]);
void  get_fsat  (l2str *l2rec, float flh[]);
void  get_fsat2 (l2str *l2rec, float flh[]);
void  get_fqy   (l2str *l2rec, float fqy[]);
void  get_fqy2  (l2str *l2rec, float fqy[]);
void  get_ipar  (l2str *l2rec, float ipar[]);
void  get_ipar2  (l2str *l2rec, float ipar[]);
void  get_depth (l2str *l2rec, float depth[]);
void  get_par   (l2str *l2rec, float par[]);
void  get_angstrom (l2str *l2rec, int band, float angst[]);
void  get_ms_epsilon(l2str *l2rec, float eps[]);
void  get_es (l2str *l2rec, int band, float es[]);
void  get_toa_refl (l2str *l2rec, int band, float rhot[]);
void  get_dust_index (l2str *l2rec, float dust[]);
void  get_ndvi (l2str *l2rec, float ndvi[]);
void  get_evi (l2str *l2rec, float evi[]);
void  get_smoke (l2str *l2rec, float smoke[]);
void  get_Kd(l2str *l2rec, l2prodstr *p, float Kd[]);
void  get_photic_depth(l2str *l2rec, l2prodstr *p, float Z[]);
void  cdom_morel(l2str *l2rec, l2prodstr *p, float prod[]);
void  get_soa(l2str *l2rec, int32_t prodID, float prod[]);
int   run_soa_sma(l2str *l2rec, int32_t ip);
void  vcal(l2str *l2rec, l2prodstr *p, float vcal[]);
double *get_xcal(l1str *l1rec, int type, int bandnum);

float aw_spectra (int32_t wl, int32_t width);
float bbw_spectra(int32_t wl, int32_t width);
void  get_aw_bbw(l2str *l2rec, float wave[], int nwave, float *aw, float *bbw);
float seawater_nsw (float wave, float sst, float sss, float *dnswds); 
float seawater_bb (float wave, float sst, float sss); 
void seawater_set(l1str *l1rec);
float seawater_get_n(int32_t ivar, int32_t ip, int32_t ib);
float seawater_get_a(int32_t ivar, int32_t ip, int32_t ib);
float seawater_get_bb(int32_t ivar, int32_t ip, int32_t ib);

int   atmocor1_land(instr *input, l1str *l1rec, int32_t ip);
void  radcor(l1str *l1rec, int32_t ip, int land);
void  polcor(l1str *l1rec, int32_t ip);
int   get_rhos(l1str *l1rec, int32_t ip);
int8  *get_qual_sst (l2str *l2rec);
int8  *get_qual_sst4(l2str *l2rec);
int16 *get_flags_sst (l2str *l2rec);
int16 *get_flags_sst4(l2str *l2rec);
float *get_sst (l2str *l2rec);
float *get_sst4(l2str *l2rec);
float *get_bias_sst (l2str *l2rec);
float *get_bias_sst4(l2str *l2rec);
float *get_stdv_sst (l2str *l2rec);
float *get_stdv_sst4(l2str *l2rec);
void  radiance2bt(l1str *l1rec, int resolution);
float get_sstref(char *file, float lon, float lat, int day);
float get_sssref(char *file, float lon, float lat, int day);
void  calcite ( l2str *l2rec, l2prodstr *p, float caco3[]);
void  tindx_morel(l2str *l2rec, int32_t ip, float *tindx);
void  tindx_shi  (l2str *l2rec, int32_t ip, float *tindx);
float conv_rrs_to_555(float Rrs, float wave);

float water_vapor(int ib, float wv, float airmass);
int ice_mask_init(char *file, int year, int day, float threshold);
char ice_mask(float lon, float lat);
float ice_fraction(float lon, float lat);
void get_ice_frac(l2str *l2rec, float ice[]);
void get_tauc(l2str *l2rec, float tauc[]);
void get_gsm(l2str *l2rec, l2prodstr *p, float prod[]);
int16 *get_iter_gsm(l2str *l2rec);
void iops_gsm(l2str *l2rec);
void get_giop(l2str *l2rec, l2prodstr *p, float prod[]);
int16 *get_iter_giop(l2str *l2rec);
int16 *get_flags_giop(l2str *l2rec);
void iops_giop(l2str *l2rec);
void get_carder(l2str *l2rec, l2prodstr *p, float prod[]);
int16 *get_flags_carder(l2str *l2rec);
void iops_carder(l2str *l2rec);
void chl_carder_empirical(l2str *l2rec,float prod[]);
void get_pml(l2str *l2rec, l2prodstr *p, float prod[]);
void iops_pml(l2str *l2rec);
void get_qaa(l2str *l2rec, l2prodstr *p, float prod[]);
unsigned char *get_flags_qaa(l2str *l2rec);
void iops_qaa(l2str *l2rec);
void get_niwa(l2str *l2rec, l2prodstr *p, float prod[]);
void iops_niwa(l2str *l2rec);
int16 *get_flags_niwa(l2str *l2rec);
void iops_las(l2str *l2rec);
int get_bbp_qaa(l2str *l2rec, int ip, float tab_wave[], float tab_bbp[], int tab_nwave);
int get_bbp_las(l2str *l2rec, int ip, float tab_wave[], float tab_bbp[], int tab_nwave);
float get_bbp_las_eta(l2str *l2rec, int ip);
void get_iops(l2str *l2rec, int32_t iop_opt);
void set_iop_flag(float32 wave[], int32 nwave, 
                  float32 a[], float32 aph[], float32 adg[], 
                  float32 bb[], float32 bbp[],int16 *flag);
float aph_bricaud(float wave, float chl);
float aph_ciotti(float wave, float sf);
float get_aphstar(float wave, int dwave, int ftype, float proxy);
float rrs_above_to_below(float Rrs); 
void optical_class(l2str *l2rec, l2prodstr *p, float prod[]);
float *get_class_ward_owmc(l2str *l2rec);
float *get_class_k_owmc(l2str *l2rec);
float *get_class_34k_w_owmc(l2str *l2rec);

void  myprod1 (l2str *l2rec, float prod[]);
void  myprod2 (l2str *l2rec, float prod[]);
void  myprod3 (l2str *l2rec, float prod[]);
void  myprod4 (l2str *l2rec, float prod[]);
void  myprod5 (l2str *l2rec, float prod[]);
void  myprod6 (l2str *l2rec, float prod[]);
void  myprod7 (l2str *l2rec, float prod[]);
void  myprod8 (l2str *l2rec, float prod[]);
void  myprod9 (l2str *l2rec, float prod[]);
void  myprod10(l2str *l2rec, float prod[]);

int get_f0_neckel   (int32_t wl, int32_t width, float *f0);
int get_f0_thuillier(int32_t wl, int32_t width, float *f0);
int get_f0_thuillier_ext(int32_t wl, int32_t width, float *f0);

float32 westernmost( float32 lon1, float32 lon2 );
float32 easternmost( float32 lon1, float32 lon2 );

/* Filter functions */

void  fctl_init(fctlstr *fctl);
int   fctl_set (fctlstr *fctl, int32_t npix, char *fname, 
                int32_t band, int32_t nx, int32_t ny, int32_t minfill);
void  filter(fctlstr *fctl, l1qstr *l1que, l1str *l1rec);
int   rdfilter( char *file, fctlstr *fctl );
void  fdilate (l1qstr *l1que,int32_t nx,int32_t ny,int flag,char kernel[],l1str *l1rec);
void  fclean  (l1qstr *l1que,int32_t nx,int32_t ny,int flag,char kernel[],l1str *l1rec);
void  fLTmean (l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fLTRmean(l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fLTmed  (l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fLTRmed (l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fEPSmean(l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fEPSiqmean(l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fLTRiqmean(l1qstr *l1que,int32_t nx,int32_t ny,int ib,int32_t minfill,char kernel[],l1str *l1rec);
void  fLTrat(l1qstr *l1que,int32_t nx,int32_t ny,l1str *l1rec);

/* viirs pixel conversion */
void viirs_pxcvt_2uag( int, int *, int * );
void viirs_pxcvt_2ag( int, int * );
void viirs_pxcvt_agdel( int, int, int * );

/* Fortran functions called from C */

void   sunangs_( int *, int *, float *, float *, float *, float *, float * );
int    getglint_(float *, float *, float *, float *, float *, float *);
int    getglint_iqu_(float *, float *, float *, float *, float *, float *, float *, float *);
double esdist_( int32_t *year, int32_t *day, int32_t *msec);
int    get_dem_height_(
  	      char  *demfile,
              float *lon, 
              float *lat, 
              float *senz,
              float *sena,
              float *height,   
              int32_t  *status);

void get_um_prod_(int32_t* idProd, int32_t* pix, float* val);
void clear_um_prod_();
int atmcor_soa_(
	      int32_t  *sensorID,
              char  *sensorNm, 
              int32_t  *nwave, 
              float *wave, 
              int32_t  *scan, 
              int32_t  *pixel,
              float *solz, 
              float *senz, 
              float *raz,
              float *lat,
              float *lon,
              float *Lt,
              float *rho_r,
              float *Fo,
              float *Tau_r,
              float *aw, 
              float *bbw, 
              float *aphstar, 
              float *adg_s, 
              float *bbp_s, 
              float *Rs,
              float *Rw,
              float *wv,
              float *t_sen,
              float *t_sol,
              float *optTaua,
              float *optW0,
              float *optChl,
              float *optAcdm,
              float *pcentCDM,
              float *optBbp,
              float *optMr,
              float *optMi,
              float *optV,
              int32_t  *status);

void get_fdiff(l2str *l2rec, float fdiff[]);

void get_cdom_morel(l2str *l2rec, l2prodstr *p, float prod[]);

void optical_water_type(l2str *l2rec, l2prodstr *p, void *vptr);

VOIDP prodgen( l2prodstr *p, l2str *l2rec);

void virtual_constellation(l2str *l2rec, l2prodstr *p, float prod[]);

extern int32_t * year_hy1c_tp;
extern int32_t * day_hy1c_tp;
#endif




